<!--
 * @Author: N0ts
 * @Date: 2024-01-29 15:04:41
 * @Description: main
 * @FilePath: \eazy-gitee-note\src\App.vue
 * @Mail：mail@n0ts.top
-->

<template>
    <div id="app2">
        <!-- 加载 -->
        <div class="loading" v-if="!Trees">
            <p>加载中</p>
        </div>
        <!-- 主体 -->
        <div
            class="main"
            v-else
            v-loading="loadContent"
            element-loading-text="全力加载中..."
        >
            <!-- 左侧 -->
            <div :class="{ leftMenu: true, leftMenuHide: menuShow }" v-cloak>
                <!-- 菜单 -->
                <el-tabs v-model="treeMenu">
                    <!-- 文件树 -->
                    <el-tab-pane label="文件" name="文件">
                        <!-- 搜索框 -->
                        <el-input
                            v-model="treeSearchText"
                            placeholder="搜一下下？"
                            :prefix-icon="Search"
                            @keyup.esc="treeSearchText = ''"
                            class="treeSearch"
                            size="small"
                        />
                        <div class="trees">
                            <!-- 文件列表头部 -->
                            <div class="treesHead">
                                <a :href="Trees.giteeURL" target="_blank">
                                    <i class="fa fa-folder-open"></i>
                                    {{ Trees.sha }}
                                </a>
                            </div>
                            <!-- 文件列表 -->
                            <div
                                :class="{
                                    treesItem: true,
                                    treesItemActive: index == contentSelectIndex
                                }"
                                v-for="(item, index) in Trees.tree"
                                @click="getContents(item.path, index)"
                                :key="index"
                            >
                                <i class="fa fa-file-code-o"></i>
                                <span
                                    v-html="item.lighthigh ?? item.path"
                                ></span>
                            </div>
                            <div
                                class="treesItem"
                                v-if="Trees.tree.length == 0"
                            >
                                暂无数据哦
                            </div>
                        </div>
                    </el-tab-pane>
                    <!-- 目录 -->
                    <el-tab-pane label="目录" name="目录">
                        <div class="contentTrees">
                            <div
                                :class="{
                                    contentItem: true,
                                    contentItemActive: index == menuSelectIndex,
                                    [item.tagName]: true
                                }"
                                v-for="(item, index) in menuData"
                                :key="index"
                                @click="menuSelect(index)"
                            >
                                {{ item.textContent }}
                            </div>
                        </div>
                    </el-tab-pane>
                </el-tabs>
                <!-- 底部菜单 -->
                <div class="bottomMenu">
                    <div content="回到顶部" @click="backTop(0)">
                        <i class="fa fa-angle-up"></i>
                    </div>
                    <div
                        content="收起菜单"
                        @click="menuShowOrHide"
                        v-if="menuShow"
                    >
                        <el-icon>
                            <ArrowLeft />
                        </el-icon>
                    </div>
                    <div content="展开菜单" @click="menuShowOrHide" v-else>
                        <el-icon>
                            <ArrowRight />
                        </el-icon>
                    </div>
                    <div content="更换主题" @click="loadTheme">
                        <el-icon>
                            <Sunny />
                        </el-icon>
                    </div>
                    <div
                        content="编辑笔记"
                        @click="openMonaco"
                        v-if="loginState"
                    >
                        <el-icon>
                            <Edit />
                        </el-icon>
                    </div>
                    <div content="分享此笔记" @click="shareNote">
                        <el-icon>
                            <Share />
                        </el-icon>
                    </div>
                    <div
                        content="登陆"
                        @click="loginDialog = true"
                        v-if="!loginState"
                    >
                        <el-icon>
                            <User />
                        </el-icon>
                    </div>
                    <div content="配置" @click="configDialog = true" v-else>
                        <el-icon>
                            <Setting />
                        </el-icon>
                    </div>
                </div>
            </div>
            <!-- 手机端遮罩 -->
            <div
                :class="{ peBlack: true, peBlackHide: menuShow }"
                @click="menuShowOrHide"
            ></div>
            <!-- 内容 -->
            <div class="body">
                <!-- 编辑界面 -->
                <div class="editor">
                    <!-- 编辑菜单 -->
                    <div class="editorMenu">
                        <!-- <div>
                            <el-switch
                                v-model="monacoPreview"
                                inline-prompt
                                style="
                                    --el-switch-on-color: #13ce66;
                                    --el-switch-off-color: #ff4949;
                                "
                                active-text="开启预览"
                                inactive-text="关闭预览"
                            />
                        </div> -->
                        <div @click="saveEdit">
                            <el-tooltip
                                class="box-item"
                                effect="dark"
                                content="保存到 Gitee"
                                placement="bottom"
                            >
                                <el-icon>
                                    <UploadFilled />
                                </el-icon>
                            </el-tooltip>
                        </div>
                    </div>
                    <!-- 编辑框 -->
                    <div id="container"></div>
                </div>
                <!-- 文章内容 -->
                <div
                    :class="{ content: true, contentHiddent: editorState }"
                    id="content"
                    :style="'padding-top:' + contentPaddingTop + 'px;'"
                >
                    <div v-html="content"></div>
                </div>
            </div>
        </div>
    </div>

    <!-- 登陆窗口 -->
    <el-dialog v-model="loginDialog" title="登陆 或 注册" width="320px">
        <el-form
            label-position="top"
            label-width="150px"
            :model="loginData"
            :rules="loginRules"
            ref="loginRuleFormRef"
        >
            <el-form-item label="账号" prop="username">
                <el-input v-model="loginData.username" />
            </el-form-item>
            <el-form-item label="密码" prop="password">
                <el-input v-model="loginData.password" show-password />
            </el-form-item>
            <el-form-item label="Gitee Access Token" prop="token">
                <el-input v-model="loginData.token" placeholder="注册需填写" />
            </el-form-item>
        </el-form>
        <template #footer>
            <span class="dialog-footer">
                <el-button type="primary" @click="login(loginRuleFormRef)">
                    登陆
                </el-button>
            </span>
        </template>
    </el-dialog>

    <!-- 网页配置 -->
    <el-dialog v-model="configDialog" title="设置" width="320px">
        <el-form
            ref="configRuleFormRef"
            label-width="135px"
            :model="config"
            :rules="configRules"
            prop="config"
            label-position="top"
        >
            <el-form-item label="仓库地址自动分析">
                <el-input
                    v-model="giteeURL"
                    placeholder="填入仓库地址自动分析"
                />
            </el-form-item>
            <el-form-item label="Gitee 账号" prop="gitee.owner">
                <el-input v-model="config.gitee.owner" />
            </el-form-item>
            <el-form-item label="Gitee 仓库名" prop="gitee.repo">
                <el-input v-model="config.gitee.repo" />
            </el-form-item>
            <el-form-item label="Gitee 仓库分支" prop="gitee.sha">
                <el-input v-model="config.gitee.sha" />
            </el-form-item>
        </el-form>
        <template #footer>
            <span class="dialog-footer">
                <el-popconfirm title="确定要退出登录吗？" @confirm="logout">
                    <template #reference>
                        <el-button type="danger">退出登录</el-button>
                    </template>
                </el-popconfirm>
                <el-button
                    type="primary"
                    @click="giteeDataSave(configRuleFormRef)"
                >
                    保存
                </el-button>
            </span>
        </template>
    </el-dialog>
</template>

<script lang="ts" setup>
import { ref, onMounted, reactive, watch } from "vue";
import axios from "axios";
import { Base64 } from "js-base64";
import MarkdownIt from "markdown-it";
import Viewer from "viewerjs";
import "viewerjs/dist/viewer.css";
import themeUtil from "@/utils/themeUtil";
import hljs from "highlight.js";
import Clipboard from "clipboard";
import {
    Share,
    Edit,
    ArrowLeft,
    ArrowRight,
    Sunny,
    UploadFilled,
    User,
    Setting,
    Search
} from "@element-plus/icons-vue";
import * as monaco from "monaco-editor";
import { ElMessage } from "element-plus";
import type { FormInstance } from "element-plus";

// 添加请求拦截器
axios.interceptors.request.use(
    function (config) {
        // 在发送请求之前做些什么
        loadContent.value = true;
        return config;
    },
    function (error) {
        // 对请求错误做些什么
        loadContent.value = false;
        return Promise.reject(error);
    }
);

// 添加响应拦截器
axios.interceptors.response.use(
    function (response) {
        // 2xx 范围内的状态码都会触发该函数。
        // 对响应数据做点什么
        loadContent.value = false;
        return response.data;
    },
    function (error) {
        // 超出 2xx 范围的状态码都会触发该函数。
        // 对响应错误做点什么
        loadContent.value = false;
        return Promise.resolve(error.response);
    }
);

onMounted(() => {
    themeUtil.load();

    init();

    // 根据屏幕宽度决定菜单收缩状态
    screenWidthMenuState();
    // 屏幕宽度发生变化
    window.onresize = () => {
        screenWidthMenuState();
    };
});

const md = new MarkdownIt();

const config = reactive({
    // Gitee 配置
    gitee: {
        // 账号
        owner: "n0ts",
        // 仓库名称
        repo: "note",
        // 分支名
        sha: "master"
    },
    // 后端地址
    serverBase: "https://api.n0ts.top",
    // 主题配置
    Themes: ["default-light", "default-dark"]
});

// 仓库下的所有文件
const Trees = ref<any>(null);
// 当前内容
const content = ref("");
// 当前选择的文件
const contentSelectIndex = ref<number>(-1);
// 菜单默认选择
const treeMenu = ref("文件");
// 笔记加载遮罩
const loadContent = ref(false);
// 文章目录数据
const menuData = ref<any>(null);
// 当前目录选择索引
const menuSelectIndex = ref(0);
// 菜单是否展开
const menuShow = ref(true);
// 计算屏幕长度，防抖
const timeOut = ref();
// 计算内容滚动距离，防抖
const timeOut2 = ref();
// 子文件夹路径
const childFile = ref();
// 图片集
const ViewerUtil = ref();
// 内容页内边高度
const contentPaddingTop = ref(0);
// 当前 markdown 内容
const markdown = ref("");
// 是否启用编辑
const editorState = ref(false);
// 文章内容 Dom
const contentDom = ref();

/**
 * 加载主题
 */
function loadTheme() {
    themeUtil.switchTheme();
    myEditor.updateOptions({
        theme: getMonacoTheme()
    });
}

/**
 * 初始化
 */
async function init() {
    const params = getQueryParams();
    if (params.path && params.owner && params.repo && params.sha) {
        config.gitee = {
            owner: params.owner,
            repo: params.repo,
            sha: params.sha
        };
    } else {
        await initLogin();
    }

    await getTrees();
    initMonaco();
}

// 登陆状态
const loginState = ref(false);
/**
 * 是否需要登录加载数据
 */
async function initLogin() {
    const test = getUserInfo();
    if (test) {
        const userData = await getGiteeData();
        if (userData) {
            loginState.value = true;
            config.gitee = userData["eazy-note"];
        }
    }
}

/**
 * 获取缓存用户信息
 */
function getUserInfo() {
    let userLogin: any = window.localStorage.getItem("n0ts-note-user");
    if (userLogin) {
        userLogin = JSON.parse(userLogin);
        loginData.username = userLogin.username;
        loginData.password = userLogin.password;
        return userLogin;
    } else {
        return null;
    }
}

// tree 数据备份，用于搜索
let treeBackup: any[] = [];

/**
 * 获取目录 Tree
 */
async function getTrees() {
    const body: any = {
        method: "GET",
        url: `/repos/${config.gitee.owner}/${config.gitee.repo}/git/trees/${config.gitee.sha}?recursive=1`
    };

    // 如果登陆，携带上账号密码
    if (loginState.value) {
        body.username = loginData.username;
        body.password = loginData.password;
    }

    const resData: any = await axios.post(
        config.serverBase + "/api/gitee/proxy",
        body
    );

    if (resData.status && resData.status != 200) {
        if (loginState.value) configDialog.value = true;
        ElMessage.warning(resData.msg);
        return;
    }

    Trees.value = resData;
    console.log("🚀 树数据 | Trees.value:", Trees.value);

    // 数据验证
    if (!Trees.value.tree) {
        content.value = `## 仓库是空的？\n快去检查吧！`;
        // 设置内容
        return setContent();
    }

    // 数据过滤，保留 md 后缀的文件
    let readme = null;
    Trees.value.tree = Trees.value.tree
        .map((item: any) => {
            // README 放第一
            if (item.path == "README.md") {
                readme = item;
                return null;
            }
            if (
                item.path.substring(item.path.length - 3, item.path.length) ==
                ".md"
            ) {
                return item;
            }
        })
        .filter(Boolean);
    if (readme) Trees.value.tree.unshift(readme);

    if (Trees.value.tree.length == 0) {
        return (content.value = "<h2>这里空空如也～</h2><p>快去写点东西吧</p>");
    }

    // 保存 tree 数据
    treeBackup = JSON.parse(JSON.stringify(Trees.value.tree));

    // 获取仓库具体路径下的内容
    const querys = getQueryParams();
    if (querys.path) {
        getContents(querys.path);
    } else if (readme) {
        getContents("README.md");
    } else {
        getContents(Trees.value.tree[0].path);
    }
}

// 文件数搜索关键词
const treeSearchText = ref("");
let treeSearchTimeout: number | undefined;
watch(
    () => treeSearchText.value,
    () => {
        if (treeSearchTimeout) {
            clearTimeout(treeSearchTimeout);
        }
        treeSearchTimeout = setTimeout(() => {
            if (!treeSearchText.value) {
                Trees.value.tree = treeBackup;
                return refreshPathIndex();
            }

            let cache: any;
            Trees.value.tree = treeBackup
                .map((tree: any) => {
                    cache = JSON.parse(JSON.stringify(tree));
                    const index = cache.path
                        .toUpperCase()
                        .indexOf(treeSearchText.value.toUpperCase());
                    if (index != -1) {
                        const key = cache.path.substring(
                            index,
                            index + treeSearchText.value.length
                        );
                        cache.lighthigh = cache.path.replace(
                            key,
                            `<span style="color: red;">${key}</span>`
                        );
                        return cache;
                    }
                })
                .filter(Boolean);
            refreshPathIndex();
        }, 100);
    }
);

// 当前文件路径
const currentPath = ref("");

/**
 * 根据当前文件路径定位索引
 */
function refreshPathIndex() {
    for (let i = 0; i < Trees.value.tree.length; i++) {
        if (Trees.value.tree[i].path == currentPath.value) {
            contentSelectIndex.value = i;
            return;
        }
    }
    contentSelectIndex.value = -1;
}

/**
 * 获取仓库具体路径下的内容
 * @param {*} path 文件名
 * @returns 文件数据
 */
async function getContents(path: string, index?: number) {
    console.log("当前获取文件路径", path);

    // 索引修改 & 是否重复
    if (contentSelectIndex.value == index) {
        return;
    }

    currentPath.value = path;

    if (index != null) {
        contentSelectIndex.value = index;
    } else {
        refreshPathIndex();
    }

    // 数据验证
    if (!path) {
        return;
    }

    // 子文件夹路径获取
    childFile.value = path.includes("/")
        ? path.substring(0, path.lastIndexOf("/"))
        : "";

    const body: any = {
        method: "GET",
        url:
            `/repos/${config.gitee.owner}/${config.gitee.repo}/contents/` +
            encodeURIComponent(path)
    };

    // 如果登陆，携带上账号密码
    if (loginState.value) {
        body.username = loginData.username;
        body.password = loginData.password;
    }

    const res: any = await axios.post(
        config.serverBase + "/api/gitee/proxy",
        body
    );
    Trees.value.tree[contentSelectIndex.value].sha = res.sha;

    // 存储 markdown 格式
    markdown.value = content.value = Base64.decode(res.content);

    // 是否存在内容
    if (!content.value || content.value.trim() == "") {
        content.value = `## 这里空空如也～\n没写点东西还好意思上传？`;
    }

    // 设置内容
    setContent();

    // 滚动条回到顶部
    backTop(0);
}

/**
 * 设置内容
 */
function setContent() {
    // md 保存到 编辑器
    editContent.value = content.value;

    // 转换为 html，超链接新建页面打开
    markdownRender(content.value);

    setTimeout(() => {
        // 获取文章目录
        getContentMenu();

        // 文章内图片查看加载
        loadImgView();

        // 监听内容区滚动条
        listenContentScroll();

        // 编辑器初始化
        initMonaco();
    }, 0);
}

/**
 * markdown 内容渲染
 * @param {string} data markdown
 */
function markdownRender(data: string) {
    content.value = md.render(data).replace(/<a /g, "<a target='_blank' ");

    // 转换后是否为空
    if (!content.value || content.value.trim() == "") {
        content.value =
            "<h2>这里空空如也～</h2><p>没写点东西还好意思上传？</p>";
    }

    // 获取内容中全部图片的 src
    content.value.replace(
        /<img [^>]*src=['"]([^'"]+)[^>]*>/gi,
        (match, capture) => {
            // 是否为 url
            let testVol =
                // eslint-disable-next-line
                /^(http|https):\/\/(([\w-]+\.)+[\w-]+|localhost)(\/[\w-.\/?%&=]*)?$/.test(
                    capture
                );

            // 不是 url 则添加仓库链接
            if (!testVol) {
                const url = `https://gitee.com/${config.gitee.owner}/${config.gitee.repo}/raw/${config.gitee.sha}${childFile.value}/${capture}`;
                let replacement = `https://api.n0ts.top/api/gitee/img?url=${encodeURIComponent(
                    url
                )}`;
                content.value = content.value.replace(capture, replacement);
            }

            return match;
        }
    );

    setTimeout(() => {
        // 索引复原
        menuSelectIndex.value = 0;

        // 代码高亮
        hljsInit();
    }, 0);
}

/**
 * 代码高亮
 */
async function hljsInit() {
    const dom: any = [];
    const codeBlocks = document.querySelectorAll("#content pre code");
    codeBlocks.forEach((cache) => {
        const item = cache as HTMLElement;
        if (item.getAttribute("class")?.includes("hljs")) {
            return;
        }
        const copyBtn = document.createElement("div");
        copyBtn.className = "copyBtn";
        copyBtn.innerHTML = "复制";
        copyBtn.setAttribute("code", item.innerText);
        copyBtn.addEventListener("click", (e) => {
            copyCode(e);
        });
        item.parentElement?.appendChild(copyBtn);
        hljs.highlightElement(item as HTMLElement);
        dom.push(item);
    });
    addCodeNum(dom);
}

/**
 * 添加代码行号
 */
function addCodeNum(dom: any) {
    for (let i = 0; i < dom.length; i++) {
        const enter = dom[i].innerHTML.replace(/\n/g, "</li><li>");
        dom[i].innerHTML = `<ol><li>${enter}</li></ol>`.replace(
            "<li></li></ol>",
            "</ol>"
        );
    }
}

/**
 * 复制代码块
 */
function copyCode(el: MouseEvent) {
    const code = (el.target as HTMLElement).getAttribute("code");
    if (code) {
        Clipboard.copy(code);
    }
    ElMessage.success("复制成功");
}

/**
 * 获取文章目录
 */
function getContentMenu() {
    menuData.value = null;
    let dom = contentDom.value.querySelectorAll("h1, h2, h3, h4");
    menuData.value = [...dom].map((item) => {
        // 获取标签名，内容，距离顶边高度
        let { tagName, textContent, offsetTop } = item;
        return {
            tagName,
            textContent,
            offsetTop
        };
    });
}

/**
 * 文章内图片查看加载
 */
function loadImgView() {
    if (!ViewerUtil.value) {
        return (ViewerUtil.value = new Viewer(
            document.querySelector("#content") as HTMLElement
        ));
    }
    ViewerUtil.value.update();
}

/**
 * 监听内容区滚动条
 */
function listenContentScroll() {
    contentDom.value.addEventListener("scroll", (e: any) => {
        if (timeOut2.value) {
            clearTimeout(timeOut2.value);
        }
        timeOut2.value = setTimeout(() => {
            // 计算高度增加一丢丢
            let top = e.target.scrollTop + 30;

            // 实时获取标题元素
            let dom = contentDom.value.querySelectorAll("h1, h2, h3, h4");
            let trees = [...dom].map((item) => {
                return item.offsetTop;
            });

            // 第一个标题高度处理
            let oneTitle = window.getComputedStyle(dom[0]).marginTop;
            oneTitle = Number(
                oneTitle.substring(0, oneTitle.length - 2)
            ).toString();
            if ((trees[0] - contentPaddingTop.value).toString() == oneTitle) {
                trees[0] = 0;
            }

            // 遍历判断当前高度对应标题位置
            for (let i = 0; i < trees.length; i++) {
                // 当滚动高度大于对应索引改变高亮
                if (top >= trees[i]) {
                    menuSelectIndex.value = i;
                }
            }
        }, 50);
    });
}

/**
 * 滚动条到指定位置
 */
function backTop(top: number) {
    if (!contentDom.value) {
        contentDom.value = document.querySelector("#content");
    }
    contentDom.value.scrollTo({
        top,
        behavior: "smooth"
    });
}

/**
 * 目录选择
 * @param {*} i 索引
 */
function menuSelect(i: number) {
    // 设置索引高亮
    menuSelectIndex.value = i;

    // 获取滚动高度
    let top = contentDom.value.querySelectorAll("h1, h2, h3, h4")[i].offsetTop;

    contentDom.value.scrollTo({
        top,
        behavior: "smooth"
    });
}

/**
 * 菜单展开与隐藏
 */
function menuShowOrHide() {
    menuShow.value = !menuShow.value;
}

/**
 * 根据屏幕宽度决定菜单收缩状态
 * 用于动态自适应
 */
function screenWidthMenuState() {
    if (timeOut.value) {
        clearTimeout(timeOut.value);
    }
    let state = document.body.clientWidth <= 820;
    timeOut.value = setTimeout(() => {
        // 当屏幕小于820 且 菜单是打开的情况下
        if (state && menuShow.value) {
            menuShowOrHide();
        }
    }, 100);
}

/**
 * 编辑框保存到码云
 */
async function saveEdit() {
    if (!loginState.value) {
        return ElMessage.warning("请登录后再进行保存");
    }

    // md.replace(
    //     // eslint-disable-next-line no-useless-escape
    //     /(http|https):\/\/(([\w-]+\.)+[\w-]+|localhost)(\/[\w-.\/?%&=]*)/gi,
    //     (match, capture) => {
    //         if (
    //             match.indexOf("https://api.n0ts.top/api/gitee/img?url=") == -1
    //         ) {
    //             return match;
    //         }

    //         const giteeUrl = decodeURIComponent(
    //             match.replace("https://api.n0ts.top/api/gitee/img?url=", "")
    //         );
    //         console.log(giteeUrl);

    //         return match;
    //     }
    // );

    const file = Trees.value.tree[contentSelectIndex.value];

    const data = await axios.post(config.serverBase + "/api/gitee/proxy", {
        username: loginData.username,
        password: loginData.password,
        method: "PUT",
        url: `/repos/${config.gitee.owner}/${config.gitee.repo}/contents/${file.path}`,
        data: {
            content: Base64.encode(myEditor.getValue()),
            sha: file.sha,
            message: `更新了 ${file.path}`
        }
    });
    if (data.status == 400)
        return ElMessage.warning("没有权限，请检查是否为自己仓库");

    await getContents(file.path);
    openMonaco();
    ElMessage.success("更新成功");
}

/**
 * 获取 url 的 query
 */
function getQueryParams() {
    let queryString = window.location.href;
    let params: any = {};

    if (!queryString) {
        return params;
    }

    // 去除开头的问号字符
    queryString = queryString.split("?")[1];
    if (!queryString) return {};

    let paramList = queryString.split("&");
    for (let i = 0; i < paramList.length; i++) {
        let param = paramList[i].split("=");
        let paramName = decodeURIComponent(param[0]);
        let paramValue = decodeURIComponent(param[1] || "");
        // 将参数名和值保存到对象中
        if (paramName) {
            params[paramName] = paramValue;
        }
    }

    return params;
}

/**
 * 分享此笔记
 */
function shareNote() {
    Clipboard.copy(
        !Trees.value.tree[contentSelectIndex.value]
            ? `${window.location.origin}?owner=${config.gitee.owner}&repo=${config.gitee.repo}&sha=${config.gitee.sha}`
            : `${window.location.origin}?path=${
                  Trees.value.tree[contentSelectIndex.value].path
              }&owner=${config.gitee.owner}&repo=${config.gitee.repo}&sha=${
                  config.gitee.sha
              }`
    );

    ElMessage.success("已复制到剪贴板");
}

// 编辑器
let myEditor: monaco.editor.IStandaloneCodeEditor;
// 编辑器内容
const editContent = ref("");
// 编辑器 Dom
const monacoDom = ref();

/**
 * 初始化编辑器，如果存在则覆盖内容
 */
function initMonaco() {
    monacoDom.value = document.getElementById("container");
    if (monacoDom.value && !myEditor) {
        myEditor = monaco.editor.create(monacoDom.value, {
            value: editContent.value,
            language: "markdown",
            automaticLayout: true,
            theme: getMonacoTheme(),
            cursorSmoothCaretAnimation: "on",
            fontLigatures: true, // 启用字体连字
            fontSize: 16, // 字体大小
            fontFamily: "'Fira Code', 'Consolas', 'Courier New', monospace", // 字体名称
            fontWeight: "normal" // 字体粗细
        });

        // 编辑器按键按下触发事件
        let timeOutLock: any = null;
        myEditor.onKeyDown(() => {
            if (timeOutLock) clearTimeout(timeOutLock);
            timeOutLock = setTimeout(() => {
                markdownRender(myEditor.getValue());
            }, 500);
        });
    } else {
        myEditor.setValue(editContent.value);
    }
}

/**
 * 获取编辑器当前主题内容
 */
function getMonacoTheme() {
    const cache = window.localStorage.getItem("n0ts-note-theme");
    return cache == "light" ? "vs" : "vs-dark";
}

/**
 * 打开或关闭编辑器
 */
function openMonaco() {
    // 切换编辑状态
    editorState.value = !editorState.value;
    // 根据编辑状态切换侧边栏展示状态
    // menuShow.value = !editorState.value;
}

// 是否开启编辑器预览
// const monacoPreview = ref(true);

// 网页设置是否打开
const configDialog = ref(false);

// 网页设置规则
const configRuleFormRef = ref<FormInstance>();
const configRules = reactive({
    gitee: {
        owner: [
            {
                required: true,
                message: "请填写 Gitee 账号",
                trigger: "change"
            }
        ],
        repo: [
            {
                required: true,
                message: "请填写 Gitee 仓库名",
                trigger: "change"
            }
        ],
        sha: [
            {
                required: true,
                message: "请填写 Gitee 仓库分支",
                trigger: "change"
            }
        ]
    }
});

// 登陆窗口是否打开
const loginDialog = ref(false);
// 登陆数据
const loginData = reactive({
    username: "",
    password: "",
    token: ""
});
// 网页设置规则
const loginRuleFormRef = ref<FormInstance>();
const loginRules = reactive({
    username: [
        {
            required: true,
            message: "请填写账号",
            trigger: "change"
        }
    ],
    password: [
        {
            required: true,
            message: "请填写密码",
            trigger: "change"
        }
    ]
});

/**
 * 登陆或注册 Gitee Token
 */
function login(formEl: FormInstance | undefined) {
    if (!formEl) return;
    formEl.validate(async (valid) => {
        if (!valid) return;
        giteeDataSave();
    });
}

/**
 * 获取 Gitee Token 数据
 */
async function getGiteeData() {
    const data = await axios.post(config.serverBase + "/api/gitee/data", {
        username: loginData.username,
        password: loginData.password
    });
    if (data.status != 200) {
        console.log("账号已失效，请重新登录", data);
        // window.localStorage.removeItem("n0ts-note-user");
        ElMessage.warning("账号已失效，请重新登录");
        return null;
    }
    return data.data;
}

/**
 * 保存数据到 Gitee Token
 */
async function giteeDataSave(formEl?: FormInstance | null) {
    async function save() {
        const postData = JSON.parse(JSON.stringify(loginData));
        if (!postData.token) {
            delete postData.token;
        }

        // 有 token 或登录状态下携带数据
        if (postData.token || loginState.value) {
            postData.jsonData = {
                "eazy-note": null
            };
            postData.jsonData["eazy-note"] = config.gitee;
        }

        const data: any = await axios.post(
            config.serverBase + "/api/gitee/data",
            postData
        );
        if (data.status != 200) {
            return ElMessage.warning(data.msg);
        }

        window.localStorage.setItem(
            "n0ts-note-user",
            JSON.stringify({
                username: loginData.username,
                password: loginData.password
            })
        );

        configDialog.value = false;
        loginDialog.value = false;

        // 没有 token 且没登录则提示
        if (!postData.token && !loginState.value) {
            ElMessage.success("登陆成功！");
        } else {
            ElMessage.success("保存成功！");
        }

        // 没登录则进行登陆
        if (!loginState.value) {
            await initLogin();
        }

        getTrees();

        giteeURL.value = "";
    }

    if (!formEl) return await save();

    formEl.validate(async (valid) => {
        if (!valid) return;
        await save();
    });
}

/**
 * 退出登录
 */
function logout() {
    window.localStorage.clear();
    ElMessage.success("已退出登录，准备刷新");
    setTimeout(() => {
        window.location.reload();
    }, 1500);
}

// 分析配置 url
const giteeURL = ref("");
watch(
    () => giteeURL.value,
    () => {
        const data = giteeURL.value.split("/").splice(3);
        if (data.length == 2) {
            config.gitee.owner = data[0];
            config.gitee.repo = data[1];
        }
    }
);
</script>
